package models;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;

import javax.persistence.*;

import play.data.validation.Required;
import play.db.jpa.Model;

@Entity
public class Plan extends Model {

	// Action plan status, true for active, false for inactive Author:
	// Youssef Selim
	private boolean status;

	// Action plan requirements Author: Youssef Selim
	private LinkedList<String> requirements;

	// Action plan name
	@Required
	private String name;

	// To-Do Items in the action plan Author: Youssef Selim
	@OneToMany(mappedBy = "plan", cascade = CascadeType.ALL)
	private List<Item> items;

	// Users working on a certain action plan Author: Youssef Selim
	@Required
	@ManyToMany
	private List<User> users;

	// Comments on the action plan Author: Youssef Selim
	@OneToMany(mappedBy = "plan", cascade = CascadeType.ALL)
	private List<Comment> comments;

	// Ideas executed in the plan Author: Youssef Selim
	@Required
	@OneToMany(mappedBy = "plan", cascade = CascadeType.ALL)
	private List<Idea> ideas;

	// Ratings on the plan Author: Youssef Selim
	@OneToMany(mappedBy = "plan", cascade = CascadeType.ALL)
	private List<Rating> ratings;

	// Organization the plan belongs to Author: Youssef Selim
	@Required
	@ManyToOne
	private Organization organization;

	// Current rating on the plan (average of all ratings). Author: Arwa Ismail
	private String averageRating = "";

	@Lob
	// Action plan timeline Author: Youssef Selim
	private LinkedList<String> timeline;

	// Date for timeline actions Author: Youssef Selim
	private Date date;

	// Plan Constructor Author: Youssef Selim
	public Plan(String name, List<Idea> ideas, Organization organization) {

		this.setDate(new Date());
		this.setTimeline(new LinkedList<String>());
		this.setName(name);
		this.setUsers(new LinkedList<User>());
		this.setOrganization(organization);
		this.setRequirements(new LinkedList<String>());
		this.setItems(new LinkedList<Item>());
		this.setComments(new LinkedList<Comment>());
		this.setIdeas(new LinkedList<Idea>());
		this.setRatings(new LinkedList<Rating>());

	}

	// Plan Constructor taking list of ideas Author: Omar Hassab
	public Plan(String name, boolean status, LinkedList<String> requirements,
			List<Idea> ideas) {
		this.setDate(new Date());
		this.setTimeline(new LinkedList<String>());
		this.setName(name);
		this.setStatus(status);
		this.setRequirements(requirements);
		this.setItems(new LinkedList<Item>());
		this.setUsers(new LinkedList<User>());
		this.setComments(new LinkedList<Comment>());
		this.setIdeas(ideas);
	}

	// Plan Default Constructor for testing purposes Author: Youssef Selim
	public Plan(String name) {
		this.setDate(new Date());
		this.setTimeline(new LinkedList<String>());
		this.setName(name);
		this.setStatus(false);
		this.setItems(new LinkedList<Item>());
		this.setUsers(new LinkedList<User>());
		this.setComments(new LinkedList<Comment>());
		this.setIdeas(new LinkedList<Idea>());
		this.setRequirements(new LinkedList<String>());
	}

	/**
	 * Calculates the current average rating of the plan
	 * 
	 * @author Arwa Ismail
	 * @version 2010.0425
	 * @category C4S10 
	 * @return void
	 */
	public void calculateAverageRating() {

		float temp = 0; // changed to float

		for (int i = 0; i < ratings.size(); i++) {
			if (ratings.get(i).getRating().equalsIgnoreCase("high"))
				temp = temp + 3;

			if (ratings.get(i).getRating().equalsIgnoreCase("medium"))
				temp = temp + 2;

			if (ratings.get(i).getRating().equalsIgnoreCase("low"))
				temp = temp + 1;
		}

		float temp2 = temp / (ratings.size());

		if (temp2 < 1.65)
			this.averageRating = "Low";
		else {
			if (temp2 < 2.35)
				this.averageRating = "Medium";
			else
				this.averageRating = "High";
		}

	}

	/**
	 * Compares two lists and returns the differences
	 * 
	 * @author Youssef Selim
	 * @version 2011.0501
	 * @return result: string of differences between the two lists
	 * */
	public static String getDiff(List one, List two) {
		String result = "";
		LinkedList oneTmp, twoTmp;
		oneTmp = new LinkedList<Object>();
		twoTmp = new LinkedList<Object>();
		if (one != null)
			for (int i = 0; i < one.size(); i++)
				oneTmp.addLast(one.get(i));
		else
			oneTmp = new LinkedList<Object>();
		for (int i = 0; i < two.size(); i++)
			twoTmp.addLast(two.get(i));
		while (!oneTmp.isEmpty())
			if (twoTmp.contains(oneTmp.get(0)))
				twoTmp.remove(oneTmp.remove(0));
			else
				result += "'" + oneTmp.remove(0).toString() + "'"
						+ " has been removed. \n";
		while (!twoTmp.isEmpty())
			result += "'" + twoTmp.remove(0).toString() + "'"
					+ " has been added. \n";
		return result;
	}

	/**
	 * Setter for Status
	 * 
	 * @author Youssef Selim
	 * @version 2011.0425
	 * @param status
	 *            : the status to set
	 */
	public void setStatus(boolean status) {
		if (this.status != status)
			this.timeline.add("Date: " + getDate().toString()
					+ " | Status changed from: "
					+ ((this.status) ? "Active" : "Inactive") + ", to: "
					+ ((status) ? "Active" : "Inactive"));
		this.status = status;

	}

	/**
	 * Getter for Status
	 * 
	 * @author Youssef Selim
	 * @version 2011.0425
	 * @return the status
	 */
	public boolean isStatus() {
		return status;
	}

	/**
	 * Setter for Requirements
	 * 
	 * @author Youssef Selim
	 * @version 2011.0425
	 * @param requirements
	 *            : the requirements to set
	 */
	public void setRequirements(LinkedList<String> requirements) {
		if (getDiff(this.requirements, requirements) != "")
			this.timeline.add("Date: " + getDate().toString()
					+ " | Requirements changes: "
					+ getDiff(this.requirements, requirements));
		this.requirements = requirements;

	}

	/**
	 * Getter for Requirements
	 * 
	 * @author Youssef Selim
	 * @version 2011.0425
	 * @return the requirements
	 */
	public LinkedList<String> getRequirements() {
		return requirements;
	}

	/**
	 * Setter for Items
	 * 
	 * @author Youssef Selim
	 * @version 2011.0425
	 * @param items
	 *            : the items to set
	 */
	public void setItems(List<Item> items) {
		if (getDiff(this.items, items) != "")
			this.timeline.add("Date: " + getDate().toString()
					+ " | Items changes: " + getDiff(this.items, items));
		this.items = items;
	}

	/**
	 * Getter for Items
	 * 
	 * @author Youssef Selim
	 * @version 2011.0425
	 * @return the items
	 */
	public List<Item> getItems() {
		return items;
	}

	/**
	 * Setter for Users
	 * 
	 * @author Youssef Selim
	 * @version 2011.0425
	 * @param users
	 *            : the users to set
	 */
	public void setUsers(List<User> users) {
		if (getDiff(this.users, users) != "")
			this.timeline.add("Date: " + getDate().toString()
					+ " | Plan Organizer/s changes: "
					+ getDiff(this.users, users));
		this.users = users;
	}

	/**
	 * Getter for Users
	 * 
	 * @author Youssef Selim
	 * @version 2011.0425
	 * @return the users
	 */
	public List<User> getUsers() {
		return users;
	}

	/**
	 * Setter for Comments
	 * 
	 * @author Youssef Selim
	 * @version 2011.0425
	 * @param comments
	 *            : the comments to set
	 */
	public void setComments(List<Comment> comments) {
		this.comments = comments;
	}

	/**
	 * Getter for comments
	 * 
	 * @author Youssef Selim
	 * @version 2011.0425
	 * @return the comments
	 */
	public List<Comment> getComments() {
		return comments;
	}

	/**
	 * Setter for Ideas
	 * 
	 * @author Youssef Selim
	 * @version 2011.0425
	 * @param ideas
	 *            : the ideas to set
	 */
	private void setIdeas(List<Idea> ideas) {
		this.ideas = ideas;
	}

	/**
	 * Getter for Ideas
	 * 
	 * @author Youssef Selim
	 * @version 2011.0425
	 * @return the ideas
	 */
	public List<Idea> getIdeas() {
		return ideas;
	}

	/**
	 * Setter for Ratings
	 * 
	 * @author Youssef Selim
	 * @version 2011.0425
	 * @param ratings
	 *            : the ratings to set
	 */
	public void setRatings(List<Rating> ratings) {
		this.ratings = ratings;
	}

	/**
	 * Getter for Ratings
	 * 
	 * @author Youssef Selim
	 * @version 2011.0425
	 * @return the ratings
	 */
	public List<Rating> getRatings() {
		return ratings;
	}

	/**
	 * Setter for Name
	 * 
	 * @author Youssef Selim
	 * @version 2011.0425
	 * @param name
	 *            : the name to set
	 */
	public void setName(String name) {
		if (this.name == null)
			this.timeline.add("Date: " + getDate().toString()
					+ " | Name added: " + name);
		else if (this.name != name)
			this.timeline.add("Date: " + getDate().toString()
					+ " | Name changed from: " + this.name + ", to: " + name);
		this.name = name;
	}

	/**
	 * Getter for name
	 * 
	 * @author Youssef Selim
	 * @version 2011.0425
	 * @return the name
	 */
	public String getName() {
		return name;
	}

	/**
	 * Getter for averageRating
	 * 
	 * @author Arwa Ismail
	 * @version 2011.0425
	 * @return the average rating
	 */

	public String getAverageRating() {
		return averageRating;
	}

	/**
	 * Setter for averageRating
	 * 
	 * @author Arwa Ismail
	 * @version 2011.0425
	 * @param averageRating
	 *            : the average rating to be set
	 */

	public void setAverageRating(String averageRating) {
		this.averageRating = averageRating;
	}

	/**
	 * Setter for Timeline
	 * 
	 * @author Youssef Selim
	 * @version 2011.0501
	 * @param timeline
	 *            : the timeline to set
	 */
	public void setTimeline(LinkedList<String> timeline) {
		this.timeline = timeline;
		this.timeline.add("Date: " + getDate().toString() + " | Plan: " + name
				+ " Created, with Status: "
				+ ((this.status) ? "Active" : "Inactive") + " & Requirements: "
				+ requirements);
	}

	/**
	 * Getter for Timeline
	 * 
	 * @author Youssef Selim
	 * @version 2011.0501
	 * @return the timeline
	 */
	public LinkedList<String> getTimeline() {
		return timeline;
	}

	/**
	 * Setter for Organization
	 * 
	 * @author Youssef Selim
	 * @version 2011.0505
	 * @param organization
	 *            : the organization to set
	 */
	public void setOrganization(Organization organization) {
		this.organization = organization;
		if(organization.getLead() != null)
		this.getUsers().add(organization.getLead());
	}

	/**
	 * * Getter for Organization
	 * 
	 * @author Youssef Selim
	 * @version 2011.0505
	 * @return the organization
	 */
	public Organization getOrganization() {
		return organization;
	}

	/**
	 * Setter for Date
	 * 
	 * @author Youssef Selim
	 * @version 2011.0505
	 * @param date
	 *            : the date to set
	 * */
	public void setDate(Date date) {
		this.date = date;
	}

	/**
	 * Getter for Date
	 * 
	 * @author Youssef Selim
	 * @version 2011.0505
	 * @return the date
	 * */
	public Date getDate() {
		return date;
	}

	public void addUser(User user) {
		if (!users.contains(user)) {
			users.add(user);
			user.addPlan(this);
		}

	}

}
